package cg.studio.model;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentLinkedQueue;

/**
 * RadomTree is tree with random number of sub-trees
 * 
 * @author brightchen
 *
 */
public class RandomTree<K, V >
{
  private V value;
  private Map< K, RandomTree<K, V> > subTrees;
  
  public RandomTree( V value )
  {
    setValue( value );
  }
  
  public RandomTree<K, V> getSubTree( K key )
  {
    if( subTrees == null )
      return null;
    return subTrees.get( key );
  }
  
  public boolean isLeaf()
  {
    return subTrees == null || subTrees.isEmpty();
  }
  
  /**
   * 
   * @param list output of the list of leaf values
   * @return
   */
  public List<V> getAllLeafValues( List<V> list )
  {
    ConcurrentLinkedQueue< RandomTree<K,V> > parentQueue = new ConcurrentLinkedQueue< RandomTree<K,V> >();
    parentQueue.add( this );
    
    while( true )
    {
      RandomTree<K,V> tree = parentQueue.poll();
      if( tree == null )    //reach end
        break;
      if( tree.isLeaf() )
      {
        list.add( tree.getValue() );
      }
      else
      {
        //this is parent, get it's sub
        parentQueue.addAll( tree.listSubTrees() );
      }
    }
    return list;
  }
  
  public List< RandomTree<K,V> > listSubTrees()
  {
    List< RandomTree<K,V> > subTreeList = new ArrayList< RandomTree<K,V> >();
    Set< Map.Entry< K, RandomTree< K, V >>> entries = subTrees.entrySet();
    for( Map.Entry< K, RandomTree< K, V >> entry : entries )
    {
      subTreeList.add( entry.getValue() );
    }
    return subTreeList;
  }
  
  public V getValue()
  {
    return value;
  }

  public void setValue( V value )
  {
    this.value = value;
  }

  public Map< K, RandomTree< K, V >> getSubTrees()
  {
    return subTrees;
  }

  public void setSubTrees( Map< K, RandomTree< K, V >> subTrees )
  {
    this.subTrees = subTrees;
  }
  
  public void addSubTree( K key, RandomTree<K, V> subTree )
  {
    if( subTrees == null )
      subTrees = new HashMap< K, RandomTree<K, V> >();
    subTrees.put( key, subTree );
  }
  
  public void addSubTree( K key, V value )
  {
    addSubTree( key, new RandomTree<K, V>( value ) );
  }
  
}
